/*
 * @copyright: Huang Ding
 * @Author: ding-cx
 * @Date: 2021-02-26 14:11:08
 * @LastEditors: ding
 * @LastEditTime: 2022-07-27 17:29:55
 * @Description: file content
 */

import { Application } from "egg";

import { checkAndMkdirLogArchive } from "./lib/core/logs-archive";
import DineggAPIClient from "./lib/core/ClusterClient/DineggAPIClient";
import DineggError from "./lib/core/DineggError";

async function moduleAppHooks(hooks: any[], hook: string) {
	// sync all hook
	// for (const oneHook of hooks) {
	//   oneHook[hook] && (await oneHook[hook]());
	// }
	// async all hook
	if (hooks.length === 0) return Promise.resolve(true);
	return new Promise((resolve) => {
		const len = hooks.length;
		let count = 0;
		hooks.forEach(async (oneHook) => {
			oneHook[hook] && (await oneHook[hook]());
			count++;
			if (count === len) {
				resolve(true);
			}
		});
	});
}

export default class AppBoot {
	app: Application;

	inst: any[];

	constructor(app: Application) {
		this.app = app;

		app.DineggError = DineggError;

		this.inst = (this.app as any).__moduleExportAppBootInstanceList;
		(app as any).__moduleExportAppBootInstanceList = undefined;
		this.registryAPIClient();
	}

	registryAPIClient() {
		const config = this.app.config?.apiClient || {};
		this.app.dineggApiClient = new DineggAPIClient(Object.assign({}, config, { cluster: this.app.cluster, app: this.app }));
	}

	configWillLoad() {
		// 执行模块导出的app.js导出的引导类的同名方法。
		this.inst?.forEach((item) => {
			item?.configWillLoad?.();
		});

		// 在中间件最前面加上登录态校验 和错误捕获，但外部可以用配置控制是否启用该中间件
		this.app.config.coreMiddleware.unshift("jwtLogin");
		this.app.config.coreMiddleware.unshift("catchNoCatchError");
	}

	configDidLoad() {
		// Config, plugin files have loaded.
		this.inst?.forEach((item) => {
			item?.configDidLoad?.();
		});
		checkAndMkdirLogArchive(this.app.config);
	}

	async didLoad() {
		this.app.logger.info("======================= %j =========================", "dinegg 应用启动 -> didLoad...");
		// All files have loaded, start plugin here.
		const inst = this.inst;
		inst && (await moduleAppHooks(inst, "didLoad"));
	}

	async willReady() {
		await this.app.dineggApiClient.ready();

		// All plugins have started, can do some thing before app ready.
		const inst = this.inst;
		inst && (await moduleAppHooks(inst, "willReady"));
	}

	async didReady() {
		// Worker is ready, can do some things
		// don't need to block the app boot.
		const inst = this.inst;
		inst && (await moduleAppHooks(inst, "didReady"));
	}

	async serverDidReady() {
		// Server is listening.
		const inst = this.inst;
		inst && (await moduleAppHooks(inst, "serverDidReady"));
		// this.app.getLogger("appStartLogger").info("[egg app config] %j", this.app.config);
		this.app.logger.info("[dinegg] 应用基本路径： %j", this.app.config.baseDir);
	}

	async beforeClose() {
		this.app.logger.info("[dinegg] 应用关闭");
		// Do some thing before app close.
		const inst = this.inst;
		inst && (await moduleAppHooks(inst, "beforeClose"));
	}
}
